package com.dny.asmtop.op;

import com.dny.asmtop.ASMMethodUtils;
import com.dny.asmtop.CB;
import com.dny.asmtop.Command;
import com.dny.asmtop.MethodContext;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.commons.GeneratorAdapter;

import java.util.Objects;

/**
 * Created by jlutt on 2018-01-17.
 * fori 操作
 * @author jlutt
 */
public class CommandFor implements Command {

  private final Command length;
  private final Command start;
  private final ForVar forVar;

  public CommandFor(Command length, ForVar forVar) {
    this.length = length;
    this.forVar = forVar;
    this.start = CB.value(0);
  }

  public CommandFor(Command start, Command length, ForVar forVar) {
    this.length = length;
    this.start = start;
    this.forVar = forVar;
  }

  @Override
  public Type type(MethodContext context) {
    return Type.VOID_TYPE;
  }

  @Override
  public Type generator(MethodContext context) {
    GeneratorAdapter g = context.getGeneratorAdapter();
    Label labelLoop = new Label();
    Label labelExit = new Label();

    VarLocal len = ASMMethodUtils.newLocal(context, Type.INT_TYPE);
    CB.add(length, start).generator(context);
    len.store(context);

    //
    start.generator(context);
    VarLocal varPosition = ASMMethodUtils.newLocal(context, Type.INT_TYPE);
    varPosition.store(context);

    g.mark(labelLoop);

    varPosition.generator(context);
    len.generator(context);

    g.ifCmp(Type.INT_TYPE, GeneratorAdapter.GE, labelExit);

    this.forVar.forLoop(varPosition).generator(context);

    varPosition.generator(context);
    g.push(1);
    g.math(GeneratorAdapter.ADD, Type.INT_TYPE);
    varPosition.store(context);

    g.goTo(labelLoop);
    g.mark(labelExit);

    return Type.VOID_TYPE;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    CommandFor that = (CommandFor) o;
    return Objects.equals(length, that.length) &&
        Objects.equals(start, that.start);
  }

  @Override
  public int hashCode() {
    return Objects.hash(length, start);
  }
}
